/*
* Copyright (c) 2020 The canvas Authors. All rights reserved.
  Use of this source code is governed by a BSD-style license that can be
  found in the LICENSE file.

* Author:         dzlua - https://gitee.com/dzlua/canvas.git
* Email:          505544956@qq.com
* FileName:       canvas.h
* Create Time:    2020/01/01 10:10:22
* Description:    /
*/

#ifndef __CANVAS_H__
#define __CANVAS_H__

/////////////////////////////////////
// osplatformutil
// see https://github.com/itas109/OSPlatformUtil
/*
   The operating system, must be one of: (I_OS_x)
     DARWIN   - Any Darwin system (macOS, iOS, watchOS, tvOS)
	 ANDROID  - Android platform
	 WIN32    - Win32 (Windows 2000/XP/Vista/7 and Windows Server 2003/2008)
	 WINRT    - WinRT (Windows Runtime)
	 CYGWIN   - Cygwin
	 LINUX    - Linux
	 FREEBSD  - FreeBSD
	 OPENBSD  - OpenBSD
	 SOLARIS  - Sun Solaris
	 AIX      - AIX
     UNIX     - Any UNIX BSD/SYSV system
*/

#define OS_PLATFORM_UTIL_VERSION 1.0.0.180723

// DARWIN
#if defined(__APPLE__) && (defined(__GNUC__) || defined(__xlC__) || defined(__xlc__))
#  include <TargetConditionals.h>
#  if defined(TARGET_OS_MAC) && TARGET_OS_MAC
#    define I_OS_DARWIN
#    ifdef __LP64__
#      define I_OS_DARWIN64
#    else
#      define I_OS_DARWIN32
#    endif
#  else
#    error "not support this Apple platform"
#  endif
// ANDROID
#elif defined(__ANDROID__) || defined(ANDROID)
#  define I_OS_ANDROID
#  define I_OS_LINUX
// Windows
#elif !defined(SAG_COM) && (!defined(WINAPI_FAMILY) || WINAPI_FAMILY==WINAPI_FAMILY_DESKTOP_APP) && (defined(WIN64) || defined(_WIN64) || defined(__WIN64__))
#  define I_OS_WIN32
#  define I_OS_WIN64
#elif !defined(SAG_COM) && (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__))
#  if defined(WINAPI_FAMILY)
#    ifndef WINAPI_FAMILY_PC_APP
#      define WINAPI_FAMILY_PC_APP WINAPI_FAMILY_APP
#    endif
#    if defined(WINAPI_FAMILY_PHONE_APP) && WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP
#      define I_OS_WINRT
#    elif WINAPI_FAMILY==WINAPI_FAMILY_PC_APP
#      define I_OS_WINRT
#    else
#      define I_OS_WIN32
#    endif
#  else
#    define I_OS_WIN32
#  endif
//CYGWIN
#elif defined(__CYGWIN__)
#  define I_OS_CYGWIN
// sun os
#elif defined(__sun) || defined(sun)
#  define I_OS_SOLARIS
// LINUX
#elif defined(__linux__) || defined(__linux)
#  define I_OS_LINUX
// FREEBSD
#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
#  ifndef __FreeBSD_kernel__
#    define I_OS_FREEBSD
#  endif
#  define I_OS_FREEBSD_KERNEL
// OPENBSD
#elif defined(__OpenBSD__)
#  define I_OS_OPENBSD
// IBM AIX
#elif defined(_AIX)
#  define I_OS_AIX
#else
#  error "not support this OS"
#endif

#if defined(I_OS_WIN32) || defined(I_OS_WIN64) || defined(I_OS_WINRT)
#  define I_OS_WIN
#endif

#if defined(I_OS_WIN)
#  undef I_OS_UNIX
#elif !defined(I_OS_UNIX)
#  define I_OS_UNIX
#endif

#ifdef I_OS_DARWIN
#define I_OS_MAC
#endif
#ifdef I_OS_DARWIN32
#define I_OS_MAC32
#endif
#ifdef I_OS_DARWIN64
#define I_OS_MAC64
#endif

/////////////////////////////////////
// for exports
#ifndef CVS_USE_STATIC

// windows
#if defined(I_OS_WIN)
  #ifdef CVS_EXPORT
    #define CVS_API __declspec(dllexport)
  #else
    #define CVS_API __declspec(dllimport)
  #endif

// linux
#elif defined(I_OS_LINUX)
  #ifdef CVS_EXPORT
    #define CVS_API __attribute__((visibility("default")))
  #else
    #define CVS_API 
  #endif

// others
#else
  #define CVS_API 

#endif

#else
  #define CVS_API 
#endif // CVS_USE_STATIC

template<typename T, unsigned int N>
char (&_cvs_array_size_fake_func(T(&)[N]))[N];

#define CVS_ArraySize(A) sizeof(_cvs_array_size_fake_func(A))

/////////////////////////////////////
// Result

#define CVS_S_RenderInternal        1100
#define CVS_S_RenderAlreadyExist    1001
#define CVS_S_RenderNotExist        1000

#define CVS_S_Ok                    0
#define CVS_E_Fail                 -1
#define CVS_E_InvalidParam         -2
#define CVS_E_OutOfMemory          -3
#define CVS_E_NotImplemented       -4
// Result render
#define CVS_E_RenderNotExist       -1000
#define CVS_E_RenderNotRender      -1001
#define CVS_E_RenderErrorType      -1002
#define CVS_E_RenderAlreadyExist   -1003
#define CVS_E_RenderNotSupported   -1004
#define CVS_E_RenderInternal       -1100

namespace cvs {
  typedef unsigned char uint8;
  typedef unsigned int uint;
  typedef unsigned long ulong;
  typedef float dtype; // float or double
  typedef int Result;

  struct IFactory;

  namespace c2d {
    struct IRender;

    enum class RenderType : uint8 {
      Default,
      D2D, Gdip, SDL
    };
  } // end namespace c2d

  namespace c3d {
    struct IRender;

    enum class RenderType : uint8 {
      Default,
      DirectX, OpenGL,
    };
  } // end namespace c3d
} // end namespace cvs

namespace cvs {
  struct CVS_API Point {
    dtype x,y;
    Point();
    Point(dtype x_, dtype y_);
    void reset(dtype x_, dtype y_);
  };

  struct CVS_API Size {
    dtype w,h;
    Size();
    Size(dtype w_, dtype h_);
    void reset(dtype w_, dtype h_);
  };

  struct CVS_API Rect {
    dtype x,y,w,h;
    Rect();
    Rect(dtype x_, dtype y_, dtype w_, dtype h_);
    Rect(const Point &pt, const Size &sz);
    Rect(const Size &sz);
    void reset(dtype x_, dtype y_, dtype w_, dtype h_);
    dtype l() const;
    dtype r() const;
    dtype t() const;
    dtype b() const;
    Point lt() const;
    Point rt() const;
    Point lb() const;
    Point rb() const;
    Size size() const;
  };

  struct CVS_API Color {
    dtype r,g,b,a;
    Color();
    Color(dtype r_, dtype g_, dtype b_, dtype a_ = 1.f);
    void reset(dtype r_, dtype g_, dtype b_, dtype a_ = 1.f);
  };

  struct CVS_API Matrix {
    dtype a,b,c,d,e,f;

    Matrix();
    Matrix(dtype a_, dtype b_, dtype c_, dtype d_, dtype e_, dtype f_);
    void reset(dtype a_, dtype b_, dtype c_, dtype d_, dtype e_, dtype f_);
    void identity();
    void multipy(const Matrix &m);
    void scale(dtype sx, dtype sy);
    void translate(dtype dx, dtype dy);
    void rotate(dtype angle);

    void transform(const Point& in, Point *out);
  };

  class CVS_API IBase {
    public:
      virtual ulong decref() = 0;
      virtual ulong incref() = 0;
  };

  class CVS_API IFactory : virtual public IBase {
    public:
      virtual Result load_render(const char *name) = 0;
      virtual Result unload_render(const char *name) = 0;
      virtual Result unload_all_render() = 0;
      virtual bool is_render_loaded(const char *name) const = 0;
      // if type is c2d::RenderType::Default, auto create by order: D2D, Gdip, SDL
      virtual Result create_2d_render(c2d::IRender **render, c2d::RenderType type = c2d::RenderType::Default) = 0;
      // if type is c3d::RenderType::Default, auto create by order: DirectX, OpenGL
      virtual Result create_3d_render(c3d::IRender **render, c3d::RenderType type = c3d::RenderType::Default) = 0;
  };
  
  CVS_API Result create_factory(IFactory **factory);
  inline bool Succeeded(const Result rst) { return ((int)rst) >= 0; }
  inline bool Failed(const Result rst) { return ((int)rst) < 0; }
  inline void SaveDecref(IBase *p) { if (p) (p)->decref(); }
} // end namespace cvs

#endif // __CANVAS_H__